#ifndef __config_H__
#define __config_H__

#include <memory>
#include <sstream>
#include <string>
#include <list>
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <functional>
#include "log.h"
#include <yaml-cpp/yaml.h>
#include <boost/lexical_cast.hpp>


namespace framework
{

class ConfigVarBase
{
public:
    using ptr = std::shared_ptr<ConfigVarBase>;

    ConfigVarBase(const std::string name, const std::string description = ""):m_name(name),m_description(description) 
    {
        //std::transform在指定的范围内应用于给定的操作，并将结果存储在指定的另一个范围内
        //::tolower表示强制使用C版本的
        std::transform(m_name.begin(), m_name.end(), m_name.begin(), ::tolower);
    }

    virtual ~ConfigVarBase() {}

    const std::string& getName() const { return m_name; }
    const std::string& getDescription() const { return m_description; }

    //转成字符串
    virtual std::string toString() = 0;
    //从字符串初始化值
    virtual bool fromString(const std::string& val) = 0;
    //返回配置参数值的类型名称
    virtual std::string getTypeName() const = 0;

protected:
    std::string m_name;         // 配置参数的名称
    std::string m_description;  // 配置参数的描述

};

//=====================================================================================================类型转换仿函数
/**
 * @brief 类型转换模板类 只能用于内置数据类型的转换
 * F 源类型, T 目标类型
 */
template<class F, class T>
class LexicalCast
{
public:
    /**
     * @brief 类型转换
     * @param[in] view 源类型值
     * @return 返回v转换后的目标类型
     * @exception 当类型不可转换时抛出异常
     */
    T operator()(const F& view)
    {
        //它可以将内置类型（如 int、double、char 等）和字符串之间进行相互转换，
        //还可以将自定义类型转换为字符串（如果该类型定义了输出运算符 <<）。
        return boost::lexical_cast<T>(view);
    }
};


//将配置文件中的值写到m_val中 string 转vector
template<class T>
class LexicalCast<std::string, std::vector<T>>
{
public:
    std::vector<T> operator()(const std::string& v)
    {
        //将字符串转换为node
        YAML::Node node = YAML::Load(v);
        typename std::vector<T> vec;
        std::stringstream ss;
        for(size_t i = 0; i < node.size(); ++i)
        {
            ss.str(""); //stringstream清空
            ss << node[i];
            vec.push_back(LexicalCast<std::string,T>()(ss.str()));
        }
        return vec;
    }    
};

// vector 转 string
template<class T>
class LexicalCast<std::vector<T>, std::string>
{
public:
    std::string operator()(const std::vector<T>& v)
    {
        YAML::Node node;
        for(auto& i : v)
        {
            node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }    
};


//将配置文件中的值写到m_val中 string 转 list
template<class T>
class LexicalCast<std::string, std::list<T>>
{
public:
    std::list<T> operator()(const std::string& v)
    {
        //将字符串转换为node
        YAML::Node node = YAML::Load(v);
        typename std::list<T> lis;
        std::stringstream ss;
        for(size_t i = 0; i < node.size(); ++i)
        {
            ss.str(""); //stringstream清空
            ss << node[i];
            lis.push_back(LexicalCast<std::string,T>()(ss.str()));
        }
        return lis;
    }    
};

// list 转 string
template<class T>
class LexicalCast<std::list<T>, std::string>
{
public:
    std::string operator()(const std::list<T>& lis)
    {
        YAML::Node node;
        for(auto& i : lis)
        {
            node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }    
};


//将配置文件中的值写到m_val中 string 转 set
template<class T>
class LexicalCast<std::string, std::set<T>>
{
public:
    std::set<T> operator()(const std::string& v)
    {
        //将字符串转换为node
        YAML::Node node = YAML::Load(v);
        typename std::set<T> s;
        std::stringstream ss;
        for(size_t i = 0; i < node.size(); ++i)
        {
            ss.str(""); //stringstream清空
            ss << node[i];
            s.insert(LexicalCast<std::string,T>()(ss.str()));
        }
        return s;
    }    
};

// set 转 string
template<class T>
class LexicalCast<std::set<T>, std::string>
{
public:
    std::string operator()(const std::set<T>& s)
    {
        YAML::Node node;
        for(auto& i : s)
        {
            node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }    
};


//将配置文件中的值写到m_val中 string 转 unordered_set
template<class T>
class LexicalCast<std::string, std::unordered_set<T>>
{
public:
    std::unordered_set<T> operator()(const std::string& v)
    {
        //将字符串转换为node
        YAML::Node node = YAML::Load(v);
        typename std::unordered_set<T> s;
        std::stringstream ss;
        for(size_t i = 0; i < node.size(); ++i)
        {
            ss.str(""); //stringstream清空
            ss << node[i];
            s.insert(LexicalCast<std::string,T>()(ss.str()));
        }
        return s;
    }    
};

// unordered_set 转 string
template<class T>
class LexicalCast<std::unordered_set<T>, std::string>
{
public:
    std::string operator()(const std::unordered_set<T>& s)
    {
        YAML::Node node;
        for(auto& i : s)
        {
            node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }    
};


//将配置文件中的值写到m_val中 string 转 map
template<class T>
class LexicalCast<std::string, std::map<std::string, T>>
{
public:
    std::map<std::string, T> operator()(const std::string& v)
    {
        //将字符串转换为node
        YAML::Node node = YAML::Load(v);
        typename std::map<std::string, T> m;
        std::stringstream ss;
        for(auto it = node.begin(); it != node.end(); ++it)
        {
            ss.str(""); //stringstream清空
            ss << it->second;
            //s.insert(LexicalCast<std::string,T>()(ss.str()));
            m.insert(std::make_pair(it->first.Scalar(), LexicalCast<std::string, T>()(ss.str())));
        }
        return m;
    }    
};

// map 转 string
template<class T>
class LexicalCast<std::map<std::string, T>, std::string>
{
public:
    std::string operator()(const std::map<std::string, T>& m)
    {
        YAML::Node node;
        for(auto& i : m)
        {
            node[i.first] = YAML::Load(LexicalCast<T, std::string>()(i.second));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }    
};


//将配置文件中的值写到m_val中 string 转 map
template<class T>
class LexicalCast<std::string, std::unordered_map<std::string, T>>
{
public:
    std::unordered_map<std::string, T> operator()(const std::string& v)
    {
        //将字符串转换为node
        YAML::Node node = YAML::Load(v);
        typename std::unordered_map<std::string, T> m;
        std::stringstream ss;
        for(auto it = node.begin(); it != node.end(); ++it)
        {
            ss.str(""); //stringstream清空
            ss << it->second;
            //s.insert(LexicalCast<std::string,T>()(ss.str()));
            m.insert(std::make_pair(it->first.Scalar(), LexicalCast<std::string, T>()(ss.str())));
        }
        return m;
    }    
};

// map 转 string
template<class T>
class LexicalCast<std::unordered_map<std::string, T>, std::string>
{
public:
    std::string operator()(const std::unordered_map<std::string, T>& m)
    {
        YAML::Node node;
        for(auto& i : m)
        {
            node[i.first] = YAML::Load(LexicalCast<T, std::string>()(i.second));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }    
};

//=====================================================================================================类型转换仿函数

/**
 * @brief 配置参数模板子类,保存对应类型的参数值
 * @details T 参数的具体类型
 *          FromStr 从std::string转换成T类型的仿函数  FromStr T operator()(const std::string)
 *          ToStr 从T转换成std::string的仿函数        ToStr std::string operator()(const T&)
 *          std::string 为YAML格式的字符串
 */
template<class T, class FromStr = LexicalCast<std::string, T>
                 ,class ToStr = LexicalCast<T, std::string> >
class ConfigVar : public ConfigVarBase
{
public:
    using RWMutexType = RWMutex;
    using ptr = std::shared_ptr<ConfigVar>;
    using on_change_cb = std::function<void (const T& old_value, const T& new_value)>;

    ConfigVar(std::string name, const T& val, std::string description = "")
        :ConfigVarBase(name,description),m_val(val) {}

    //转成字符串
    virtual std::string toString() override
    {
        try
        {
            RWMutex::ReadLock lock(m_mutex);
            return ToStr()(m_val);
        }
        catch(const std::exception& e)
        {
            FRAMEWORK_LOG_ERROR(FRAMEWORK_LOG_ROOT()) <<  "ConfigVar::toString exception"
                << e.what() << " convert: " << typeid(m_val).name() << " to string";
        }
        return "";
    }
    //从字符串初始化值
    bool fromString(const std::string& val) override
    {
        try
        {
            setValue(FromStr()(val));
            return true;
        }
        catch(const std::exception& e)
        {
            FRAMEWORK_LOG_ERROR(FRAMEWORK_LOG_ROOT()) <<  "ConfigVar::fromString exception"
                << e.what() << " convert: " << typeid(m_val).name();
        }
        return false;
    }
    
    std::string getTypeName() const override { return typeid(T).name(); }
    const T getValue() 
    {
        RWMutex::ReadLock lock(m_mutex);
        return m_val; 
    }
    void setValue(const T& v) 
    {
        {
            RWMutex::ReadLock lock(m_mutex);
            //如果配置文件没有改，值没有发生变化，直接返回
            if(v == m_val)
            {
                return;
            }
            for(auto & t : m_cbs)
            {
                t.second(m_val, v);
            }
        }

        RWMutex::WriteLock lock(m_mutex); 
        m_val = v;
    }


    //添加回调函数  返回该回调函数对应的唯一id,用于删除回调
    uint64_t addListener(on_change_cb cb)
    {
        static uint64_t s_fun_id = 0;
        RWMutex::WriteLock lock(m_mutex); 
        ++s_fun_id;
        m_cbs[s_fun_id] = cb;
        return s_fun_id;
    }

    //删除回调函数
    void delListener(uint64_t key)
    {
        RWMutex::WriteLock lock(m_mutex); 
        m_cbs.erase(key);
    }

    //获取回调函数
    on_change_cb getListener(uint64_t key)
    {
        RWMutex::ReadLock lock(m_mutex);
        auto it = m_cbs.find(key);
        return it == m_cbs.end() ? nullptr : it->second;
    }

    void clearListener()
    {
        RWMutex::WriteLock lock(m_mutex); 
        m_cbs.clear();
    }
private:
    RWMutexType m_mutex;
    T m_val;

    // 变更回调函数组 (如果配置文件发生修改，可以从新读取配置文件)
    std::map<uint64_t, on_change_cb> m_cbs;  //提示用户，配置变更了
};


class Config
{
public:
    using RWMutexType = RWMutex;
    using ConfigVarMap = std::map<std::string, ConfigVarBase::ptr>;

    /**
     * @brief 查找配置参数
     * @param[in] name 配置参数名称
     * @return 返回配置参数名为name的配置参数
     */
    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name)
    {
        RWMutex::ReadLock lock(GetMutex());
        auto it = GetDatas().find(name);
        if(it == GetDatas().end())
        {
            //如果没找到
            return nullptr;
        }
        
        //当指针是智能指针时候，向下转换，用dynamic_Cast 则编译不能通过，此时需要使用dynamic_pointer_cast。
        return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);
    }

    /**
     * @brief 获取/创建对应参数名的配置参数
     * @param[in] name 配置参数名称
     * @param[in] default_value 参数默认值
     * @param[in] description 参数描述
     * @details 获取参数名为name的配置参数,如果存在直接返回
     *          如果不存在,创建参数配置并用default_value赋值
     * @return 返回对应的配置参数,如果参数名存在但是类型不匹配则返回nullptr
     * @exception 如果参数名包含非法字符[^0-9a-z_.] 抛出异常 std::invalid_argument 无效参数
     */
    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name,
        const T& default_value, const std::string& description = "")
    {
        RWMutexType::WriteLock lock(GetMutex());
        //如果找到了
        auto it = GetDatas().find(name);
        if(it != GetDatas().end())
        {
            auto tmp = std::dynamic_pointer_cast<ConfigVar<T>>(it->second);
            if(tmp)
            {
                
                FRAMEWORK_LOG_INFO(FRAMEWORK_LOG_ROOT()) << "Lookup name = " << name << " exists";
                return tmp;
            }
            else
            { 
                FRAMEWORK_LOG_ERROR(FRAMEWORK_LOG_ROOT()) << "Lookup name = " << name << "exists but type not " 
                        << typeid(T).name() << "   real_type = " << it->second->getTypeName() << "   " << it->second->toString();
                return nullptr;
            }
        }

        //在字符串中查找第一个与str中的字符都不匹配的字符，返回它的位置。搜索从index(参数2，默认为0)开始。如果没找到就返回string::nops
        if(name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678") != std::string::npos)
        {
            FRAMEWORK_LOG_ERROR(FRAMEWORK_LOG_ROOT()) << "Lookup name invalid" << name;
            throw std::invalid_argument(name);
        }

        typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description));
        GetDatas()[name] = v;
        return v;
    }

    //使用YAML::Node初始化配置模块
    static void LoadFromYaml(const YAML::Node& root);

    //查找配置参数,返回配置参数的基类   name:配置参数名称
    static ConfigVarBase::ptr LookupBase(const std::string& name);

    //遍历配置模块里所以配置项
    static void Visit(std::function<void(ConfigVarBase::ptr)> cb);

private:
    //返回所有的配置项
    static ConfigVarMap& GetDatas() {
        static ConfigVarMap s_datas;
        return s_datas;
    }

    static RWMutexType& GetMutex()
    {
        static RWMutexType s_mutex;
        return s_mutex;
    }
};

}




#endif
